﻿using Core;
using Core.Entitys;
using Core.Tools;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace ConfigureSystem
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly List<CommandInfoBox> _CommandDataSource;
        private readonly ObservableCollection<CommandInfoBox> CommandDataSource;
        private readonly List<Predicate<CommandInfoBox>> CommandFilters;

        private readonly List<ConfigInfoBox> _ConfigDataSource;
        private readonly ObservableCollection<ConfigInfoBox> ConfigDataSource;
        private readonly List<Predicate<ConfigInfoBox>> ConfigFilters;

        private void InvokeFilters<T>(List<T> Source, ObservableCollection<T> Dest, List<Predicate<T>> Filters)
        {
            Dest.Clear();

            foreach (var Item in Source)
            {
                bool Flag = true;

                foreach (var FilterItem in Filters)
                {
                    if (!FilterItem(Item))
                    {
                        Flag = false;

                        break;
                    }
                }

                if (Flag)
                {
                    Dest.Add(Item);
                }
            }
        }

        private bool _IsUpdate;
        private bool _IsBuild;
        public bool IsUpdate
        {
            get
            {
                return _IsUpdate;
            }
            set
            {
                _IsUpdate = value;
                if (value)
                {
                    _IsBuild = false;
                }
            }
        }
        public bool IsBuild
        {
            get
            {
                return _IsBuild;
            }
            set
            {
                _IsBuild = value;
                if (value)
                {
                    _IsUpdate = false;
                }
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            var BaseProcessType = typeof(BaseProcess);

            var CommandsField = BaseProcessType.GetField("Commands", BindingFlags.Static | BindingFlags.NonPublic);

            var Commands = (Dictionary<string, CommandInfo>)CommandsField.GetValue(null);

            CommandDataSource = new ObservableCollection<CommandInfoBox>();
            _CommandDataSource = new List<CommandInfoBox>();
            CommandFilters = new List<Predicate<CommandInfoBox>>();

            foreach (var CommandItem in Commands)
            {
                var Item = new CommandInfoBox(CommandItem.Value);

                _CommandDataSource.Add(Item);
                CommandDataSource.Add(Item);
            }

            CommandDataGrid.ItemsSource = CommandDataSource;
            
            var GlobalConfigsField = BaseProcessType.GetField("GlobalConfigs", BindingFlags.Static | BindingFlags.NonPublic);

            var GlobalConfigs = (ParamDictionary<string, ConfigInfo>)GlobalConfigsField.GetValue(null);

            ConfigDataSource = new ObservableCollection<ConfigInfoBox>();
            _ConfigDataSource = new List<ConfigInfoBox>();
            ConfigFilters = new List<Predicate<ConfigInfoBox>>();

            foreach (var ConfigItem in GlobalConfigs)
            {
                var Item = new ConfigInfoBox(ConfigItem.Value);

                ConfigDataSource.Add(Item);
                _ConfigDataSource.Add(Item);
            }

            ConfigDataGrid.ItemsSource = ConfigDataSource;

            IsUpdate = false;
            IsBuild = false;
        }

        private void Command_Delete_Click(object sender, RoutedEventArgs e)
        {
            bool HasSelected = CommandDataSource.Contains(Item => Item.IsSelected);

            if (HasSelected && MessageBox.Show("Confirm delete these records?", "Operation tips", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                CommandDataSource.RemoveAll(Item =>
                {
                    return Item.IsSelected;
                });

                _CommandDataSource.RemoveAll(Item =>
                {
                    return Item.IsSelected;
                });
            }
        }

        private void Command_Add_Click(object sender, RoutedEventArgs e)
        {
            CommandInfo NewCommand = new CommandInfo("");

            CommandFrame AddFrame = new CommandFrame(NewCommand);

            AddFrame.Saved += AddCommandFrame_Saved;

            AddFrame.ShowDialog();
        }

        private void AddCommandFrame_Saved(object sender, CommandInfo e)
        {
            var Item = new CommandInfoBox(e);

            CommandDataSource.Add(Item);
            _CommandDataSource.Add(Item);

            IsUpdate = true;
        }

        private void Command_Update_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < CommandDataSource.Count; i++)
            {
                if (CommandDataSource[i].IsSelected)
                {
                    CommandFrame UpdateFrame = new CommandFrame(CommandDataSource[i].Context);

                    UpdateFrame.Saved += UpdateCommandFrame_Saved;

                    UpdateFrame.ShowDialog();
                }
            }
        }

        private void UpdateCommandFrame_Saved(object sender, CommandInfo e)
        {
            var Item = new CommandInfoBox(e);

            for (int i = 0; i < CommandDataSource.Count; i++)
            {
                if (CommandDataSource[i].Context == e)
                {
                    CommandDataSource[i] = Item;

                    break;
                }
            }

            for (int i = 0; i < _CommandDataSource.Count; i++)
            {
                if (_CommandDataSource[i].Context == e)
                {
                    _CommandDataSource[i] = Item;

                    break;
                }
            }

            IsUpdate = true;
        }

        private void Build_Click(object sender, RoutedEventArgs e)
        {
            var ConfigTemp = File.ReadAllText("TextTemp/Config.txt");
            var CommandTemp = File.ReadAllText("TextTemp/Command.txt");
            var ParamItemTemp = File.ReadAllText("TextTemp/ParamItem.txt");
            var ConfigItemTemp = File.ReadAllText("TextTemp/ConfigItem.txt");

            string Code = Helper.Format(ConfigTemp, Name =>
            {
                switch (Name)
                {
                    case "CommandIdentity":
                        return CommandInfo.Identity;
                    case "Command":
                        StringBuilder CommandText = new StringBuilder();

                        for (int Index = 0; Index < _CommandDataSource.Count; ++Index)
                        {
                            var CommandItem = _CommandDataSource[Index].Context;

                            CommandText.Append(Helper.Format(CommandTemp, Name2 =>
                            {
                                switch (Name2)
                                {
                                    case "Keys":
                                        return CommandItem.Id;
                                    case "Name":
                                        return Helper.StringEscape(CommandItem.Name);
                                    case "Description":
                                        return Helper.StringEscape(CommandItem.Description);
                                    case "Type":
                                        return CommandItem.Type;
                                    case "Sign":
                                        return (int)CommandItem.Sign;
                                    case "Code":
                                        if (CommandItem.Code == null)
                                        {
                                            return null;
                                        }
                                        return Helper.StringEscape(CommandItem.Code);
                                    case "ParamsLength":
                                        return CommandItem.Params?.Length;
                                    case "ResultsLength":
                                        return CommandItem.Results?.Length;
                                    case "Params":
                                        StringBuilder ParamsText = new StringBuilder();

                                        for (int i = 0; i < CommandItem.Params?.Length; ++i)
                                        {
                                            var ParamItem = CommandItem.Params[i];
                                            ParamsText.Append(Helper.Format(ParamItemTemp, Name3 =>
                                            {
                                                switch (Name3)
                                                {
                                                    case "Name":
                                                        return Helper.StringEscape(ParamItem.Name);
                                                    case "Sign":
                                                        return (int)ParamItem.Sign;
                                                    case "Type":
                                                        return (int)ParamItem.Type;
                                                    case "Description":
                                                        return Helper.StringEscape(ParamItem.Description);
                                                    case "Index":
                                                        return i;
                                                    default:
                                                        return null;
                                                }
                                            }));
                                        }
                                        return ParamsText.ToString();
                                    case "Results":
                                        StringBuilder ResultsText = new StringBuilder();

                                        for (int i = 0; i < CommandItem.Results?.Length; ++i)
                                        {
                                            var ResultItem = CommandItem.Results[i];
                                            ResultsText.Append(Helper.Format(ParamItemTemp, Name3 =>
                                            {
                                                switch (Name3)
                                                {
                                                    case "Name":
                                                        return Helper.StringEscape(ResultItem.Name);
                                                    case "Sign":
                                                        return (int)ResultItem.Sign;
                                                    case "Type":
                                                        return (int)ResultItem.Type;
                                                    case "Description":
                                                        return Helper.StringEscape(ResultItem.Description);
                                                    case "Index":
                                                        return i;
                                                    default:
                                                        return null;
                                                }
                                            }));
                                        }
                                        return ResultsText.ToString();
                                    case "Index":
                                        return Index;
                                    default:
                                        return null;
                                }
                            }));
                        }

                        return CommandText.ToString();
                    case "CommandsLength":
                        return _CommandDataSource.Count;
                    case "ConfigsLength":
                        return _ConfigDataSource.Count;
                    case "Configs":
                        StringBuilder ConfigsBuilder = new StringBuilder();

                        for (int Index = 0; Index < _ConfigDataSource.Count; Index++)
                        {
                            var ConfigItem = _ConfigDataSource[Index].Context;

                            ConfigsBuilder.Append(Helper.Format(ConfigItemTemp, Name2 =>
                            {
                                switch (Name2)
                                {
                                    case "Name":
                                        return Helper.StringEscape(ConfigItem.Name);
                                    case "Description":
                                        return Helper.StringEscape(ConfigItem.Description);
                                    case "Value":
                                        if (ConfigItem.Value is string)
                                        {
                                            return string.Format("\"{0}\"", Helper.StringEscape(ConfigItem.Value.ToString()));
                                        }
                                        if (ConfigItem.Value is Guid)
                                        {
                                            return string.Format("Guid.Parse(\"{0}\")", ConfigItem.Value);
                                        }
                                        if (ConfigItem.Value is DateTime)
                                        {
                                            return string.Format("new DateTime({0})", ((DateTime)ConfigItem.Value).Ticks);
                                        }
                                        if (ConfigItem.Value is bool)
                                        {
                                            return ((bool)ConfigItem.Value) ? "true" : "false";
                                        }
                                        if (ConfigItem.Value != null)
                                        {
                                            return ConfigItem.Value.ToString();
                                        }
                                        return "null";
                                    case "Index":
                                        return Index;
                                    default:
                                        return null;
                                }
                            }));
                        }

                        return ConfigsBuilder.ToString();
                    default:
                        return null;
                }
            });

            string StringBackupTime = DateTime.Now.ToString("yyyy-MM-dd HH.mm.ss");

            if (!Directory.Exists("Backup"))
            {
                Directory.CreateDirectory("Backup");
            }

            if (File.Exists("Config.txt"))
            {
                File.Move("Config.txt", "Backup\\Config " + StringBackupTime + ".txt");
            }

            if (File.Exists("Config.dll"))
            {
                File.Move("Config.dll", "Backup\\Config " + StringBackupTime + ".dll");
            }

            File.WriteAllText("Config.txt", Code);

            Helper.Compiler(Code, "Config.dll", new string[] { "System.dll", typeof(Helper).Assembly.Location });

            MessageBox.Show("Successful.");

            IsBuild = true;
        }

        private void Config_Add_Click(object sender, RoutedEventArgs e)
        {
            ConfigInfo NewConfig = new ConfigInfo();

            ConfigFrame AddFrame = new ConfigFrame(NewConfig);

            AddFrame.Saved += AddConfigFrame_Saved; ;

            AddFrame.ShowDialog();
        }

        private void AddConfigFrame_Saved(object sender, ConfigInfo e)
        {
            var Item = new ConfigInfoBox(e);

            ConfigDataSource.Add(Item);
            _ConfigDataSource.Add(Item);

            IsUpdate = true;
        }

        private void Config_Update_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < ConfigDataSource.Count; i++)
            {
                if (ConfigDataSource[i].IsSelected)
                {
                    ConfigFrame UpdateFrame = new ConfigFrame(ConfigDataSource[i].Context);

                    UpdateFrame.Saved += UpdateConfigFrame_Saved; ;

                    UpdateFrame.ShowDialog();
                }
            }
        }

        private void UpdateConfigFrame_Saved(object sender, ConfigInfo e)
        {
            var Item = new ConfigInfoBox(e);

            for (int i = 0; i < ConfigDataSource.Count; i++)
            {
                if (ConfigDataSource[i].Context == e)
                {
                    ConfigDataSource[i] = Item;
                }
            }

            for (int i = 0; i < _ConfigDataSource.Count; i++)
            {
                if (_ConfigDataSource[i].Context == e)
                {
                    _ConfigDataSource[i] = Item;
                }
            }

            IsUpdate = true;
        }

        private void Config_Delete_Click(object sender, RoutedEventArgs e)
        {
            bool HasSelected = ConfigDataSource.Contains(Item => Item.IsSelected);

            if (HasSelected && MessageBox.Show("Confirm delete these records?", "Operation tips", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                ConfigDataSource.RemoveAll(Item =>
                {
                    return Item.IsSelected;
                });

                _ConfigDataSource.RemoveAll(Item =>
                {
                    return Item.IsSelected;
                });
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (IsUpdate && !IsBuild)
            {
                switch (MessageBox.Show("The modified is no builds, Now builds and exit?", "Operation tips", MessageBoxButton.YesNoCancel))
                {
                    case MessageBoxResult.Cancel:
                        e.Cancel = true;
                        break;
                    case MessageBoxResult.Yes:
                        Build_Click(null, null);
                        break;
                }
            }

            base.OnClosing(e);
        }

        private void CommandDataGrid_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var Point = e.GetPosition(CommandDataGrid);

            var Element = CommandDataGrid.InputHitTest(Point) as DependencyObject;

            while (Element != null && !(Element is DataGridRow))
            {
                Element = VisualTreeHelper.GetParent(Element);
            }

            if (Element != null)
            {
                var DoubleClickedRow = (DataGridRow)Element;

                var CommandInfoBox = (CommandInfoBox)DoubleClickedRow.DataContext;

                var UpdateFrame = new CommandFrame(CommandInfoBox.Context);

                UpdateFrame.Saved += UpdateCommandFrame_Saved; ;

                UpdateFrame.ShowDialog();
            }
        }

        private void ConfigDataGrid_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var Point = e.GetPosition(ConfigDataGrid);

            var Element = ConfigDataGrid.InputHitTest(Point) as DependencyObject;

            while (Element != null && !(Element is DataGridRow))
            {
                Element = VisualTreeHelper.GetParent(Element);
            }

            if (Element != null)
            {
                var DoubleClickedRow = (DataGridRow)Element;

                var ConfigInfoBox = (ConfigInfoBox)DoubleClickedRow.DataContext;

                var UpdateFrame = new ConfigFrame(ConfigInfoBox.Context);

                UpdateFrame.Saved += UpdateConfigFrame_Saved; ;

                UpdateFrame.ShowDialog();
            }
        }

        private void CommandQuery_Click(object sender, RoutedEventArgs e)
        {
            if (!CommandFilters.Contains(CommandQueryFilter))
            {
                CommandFilters.Add(CommandQueryFilter);
            }

            InvokeFilters(_CommandDataSource, CommandDataSource, CommandFilters);
        }

        private bool CommandQueryFilter(CommandInfoBox CommandInfo)
        {
            string Name = CommandQueryText.Text;

            if (string.IsNullOrEmpty(Name))
            {
                return true;
            }

            return CommandInfo.Name.Contains(Name);
        }

        private void ConfigQuery_Click(object sender, RoutedEventArgs e)
        {
            if (!ConfigFilters.Contains(ConfigQueryFilter))
            {
                ConfigFilters.Add(ConfigQueryFilter);
            }

            InvokeFilters(_ConfigDataSource, ConfigDataSource, ConfigFilters);
        }

        private bool ConfigQueryFilter(ConfigInfoBox ConfigInfo)
        {
            string Name = ConfigQueryText.Text;

            if (string.IsNullOrEmpty(Name))
            {
                return true;
            }

            return ConfigInfo.Name.Contains(Name);
        }
    }

    public class CommandInfoBox
    {
        private CommandInfo _Context;

        public CommandInfoBox(CommandInfo Context)
        {
            this._Context = Context;
        }
        public CommandInfo Context
        {
            get
            {
                return _Context;
            }
        }

        public bool IsSelected { get; set; }
        public int Keys { get { return _Context.Id; } }
        public string Name { get { return _Context.Name; } }
        public int Sign { get { return (int)_Context.Sign; } }
        public string Description { get { return _Context.Description; } }
    }

    public class ConfigInfoBox
    {
        private ConfigInfo _Context;
        public bool IsSelected { get; set; }
        public string Name { get { return _Context.Name; } }
        public string Value { get { return _Context.Value == null ? "" : _Context.Value.ToString(); } }
        public string Description { get { return _Context.Description; } }
        public ParamTypes Type
        {
            get
            {
                if (_Context.Value == null)
                {
                    return (ParamTypes)0;
                }

                switch (System.Type.GetTypeCode(_Context.Value.GetType()))
                {
                    case TypeCode.Boolean:
                        return ParamTypes.Boolean;
                    case TypeCode.Int32:
                        return ParamTypes.Int;
                    case TypeCode.Int64:
                        return ParamTypes.Long;
                    case TypeCode.Single:
                        return ParamTypes.Float;
                    case TypeCode.Double:
                        return ParamTypes.Double;
                    case TypeCode.String:
                        return ParamTypes.String;
                    case TypeCode.DateTime:
                        return ParamTypes.DateTime;
                    case TypeCode.Object:
                        return ParamTypes.Object;
                    default:
                        if (_Context.Value is Guid)
                        {
                            return ParamTypes.Guid;
                        }

                        return (ParamTypes)0;
                }
            }
        }
        public ConfigInfo Context
        {
            get
            {
                return _Context;
            }
        }

        public ConfigInfoBox(ConfigInfo Context)
        {
            this._Context = Context;
        }
    }
}